# Upgrade Terraform Providers in a Terraform Module

Yes. An agent raises your module's provider constraints, validates every example on the new versions, fixes deprecated arguments and opens a pull request.

[Run this on Rush](https://cloud.getrush.ai/run/upgrade-terraform-providers/terraform/), in a Project that has your repository.

## What the agent does

The agent clones the module into its own cloud sandbox and reads every `versions.tf`, because a published module declares the providers it accepts in more than one place. In terraform-aws-modules/terraform-aws-vpc, the root `versions.tf` asks for `hashicorp/aws` `>= 6.28` with `required_version = ">= 1.0"`, and so do `modules/flow-log`, `modules/vpc-endpoints`, `wrappers` and each directory under `examples`, some of them with `required_version = ">= 1.5.7"`. The constraints are floors, not pins, and `.gitignore` excludes `.terraform.lock.hcl`, so there is no lockfile to bump. Upgrading here means testing against the newest provider and moving the floor only when the module needs it.

It runs `terraform init -upgrade` in the root and in each example (`simple`, `complete`, `ipv6-dualstack`, `ipam`, `network-acls` and the rest), records the provider version each one resolves, and then reads the provider changelog from the old floor up to that version. It searches the 74 `resource` blocks in `main.tf`, the 5 in `vpc-flow-logs.tf` and the submodules for arguments the changelog deprecates or removes, and fixes each one in the module. When a fix needs an argument that only exists in a newer provider, the agent raises the floor in every `versions.tf` that declares it, so the root module and its submodules never disagree.

Next it runs the checks the repository already defines. `.pre-commit-config.yaml` (pre-commit-terraform `v1.108.1`) runs `terraform_fmt`, `terraform_wrapper_module_for_each`, `terraform_docs`, `terraform_tflint` with a list of rules such as `terraform_required_providers` and `terraform_documented_variables`, and `terraform_validate`. `.github/workflows/pre-commit.yml` runs them twice, on the minimum and the maximum Terraform version that `clowdhaus/terraform-min-max` finds, with tflint `v0.64.0` and terraform-docs `v0.24.0`. The agent runs `terraform fmt -check -recursive`, `terraform validate` in each example and the same pre-commit hooks in the sandbox.

The prompt also asks for `terraform test`. This module has no `.tftest.hcl` files, so the agent says so instead of claiming a test pass, and lists `terraform test` as not run. Any bump that breaks validation or a hook and has no clean fix is left out of the pull request with the error and the reason.

## Start it with one API call

`POST https://api.prix.dev/o/{org}/sessions`

```json
{
  "agent": "claude",
  "input": "Upgrade the providers in this Terraform module. Read every versions.tf (root, modules/, wrappers/ and examples/) and run terraform init -upgrade in each to find the newest provider versions the constraints allow. Read each provider's changelog from the current minimum to that version, fix every deprecated or removed argument the module uses, and raise the minimum version in every versions.tf that declares the provider only where a fix needs it. Run terraform fmt -check -recursive, terraform validate in every example, the pre-commit hooks in .pre-commit-config.yaml, and terraform test if any .tftest.hcl files exist. Leave out any upgrade that breaks them and say why. Open a pull request with one line per provider: old minimum, new minimum or unchanged, the version tested, and each argument fixed.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-module"
    }
  ]
}
```

1. **Get an API key.** In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
2. **Send the request.** POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
3. **Read what came back.** Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

## What comes back

What comes back is a pull request on a new branch. It holds the argument fixes in `main.tf`, `vpc-flow-logs.tf` or the submodules, the raised `version` constraints in each `versions.tf` that needed one, and whatever `terraform_docs` regenerated in the README files as a result. The description has one line per provider with the old floor, the new floor or unchanged, and the version the examples were validated against, then the list of fixes and any bump left out with its error.

The checks are the repository's own pre-commit workflow on the minimum and maximum Terraform versions, the same hooks the agent ran. The session's transcript keeps every `terraform init -upgrade`, `validate` and pre-commit run with its output, so a reviewer can see which provider version each example resolved.

Before merging, a reviewer checks that a raised floor is justified by a fix in the same diff, since raising it forces every caller of the module to upgrade too. They read each argument change for a behavior change the changelog mentions, because `terraform validate` proves the configuration is well formed, not that a plan against a real account changes nothing.

## Run it on every Monday morning

The AWS provider releases often, so a weekly run keeps the module ahead of deprecations without anyone reading changelogs by hand. A scheduled job can send this request every Monday for each module repository, with an `Idempotency-Key` built from the repository and the week so a retried request returns the run already started.

With a webhook URL on the API key, Rush posts `run.completed` or `run.failed` when the run's turn finishes. Your handler reads the session from `session_url` and posts the pull request link to the channel that owns the module, or does nothing when the run found no change worth making.

## Why run it on Rush?

Provider upgrades need a clean plugin cache: `terraform init -upgrade` downloads each provider fresh, and a laptop's `~/.terraform.d` or an old `.terraform` directory can hide a version mismatch. In a Rush sandbox the agent installs Terraform, tflint and terraform-docs at the versions the workflow names and initialises every example from nothing.

A bot that opens one red pull request per version bump gets ignored. Here the agent does what a reviewer would do first, reading the changelog and validating each example, and the transcript keeps every command's output as the record. Several module repositories can run at once, each in its own sandbox.

## Frequently asked questions

### Does it need AWS credentials?

No. `terraform init`, `fmt`, `validate`, tflint and terraform-docs all run without credentials. The agent does not run `plan` or `apply` against an account unless you ask and give it credentials.

### Why not just pin the newest provider version?

A reusable module should accept the widest range of providers it works with, so callers can choose their own versions in their lockfiles. The agent raises the minimum only when a fix requires it, and tests against the newest version.

### My module has no terraform test files. Is that a problem?

The upgrade still runs, but `terraform test` has nothing to execute, and the pull request says so. You can ask in a follow-up for plan-mode tests in a `tests/` directory, which run without credentials using mocked providers.

### Will it work with OpenTofu?

Name OpenTofu in the prompt and the agent runs `tofu init -upgrade` and `tofu validate` instead. Provider sources and constraints read the same way in both.
