Skip to content

fix(terraform): support direct OpenTofu registry h1 hashes fetch (#9213) - #9611

Open
prajaktaukirde wants to merge 5 commits into
updatecli:mainfrom
prajaktaukirde:fix-opentofu-lock-hashes
Open

prajaktaukirde wants to merge 5 commits into
updatecli:mainfrom
prajaktaukirde:fix-opentofu-lock-hashes

Conversation

@prajaktaukirde

Copy link
Copy Markdown

Fix #9213

This PR fixes the issue where running UpdateCli against the OpenTofu provider registry (registry.opentofu.org) only records the requested platform's h1 hashes. Because the OpenTofu registry serves h1 hashes for all published platforms directly in its download metadata response (under the packages dictionary), a subsequent local tofu init expands the lock file's h1 set to match the full platform list, leading to a perpetual mismatch and a "dirty" lock file.

To resolve this, we:

  • Intercept lock queries targeting registry.opentofu.org.
  • Fetch the provider versions metadata and pick a supported platform.
  • Query download metadata for that platform, which yields the packages dictionary containing both h1 and zh hashes for all published platforms.
  • Sort, deduplicate, and record these hashes to match tofu init's behavior exactly, avoiding any binary downloads.
  • Fall back to the default tfupdate downloader behaviour in case of failure.

Test

To test this pull request, you can run the following commands:

cd pkg/plugins/resources/terraform/lock
go test -v .

}

urlVersions := fmt.Sprintf("%s://%s/v1/providers/%s/%s/versions", scheme, t.provider.Hostname, t.provider.Namespace, t.provider.Type)
req, err := http.NewRequestWithContext(context.Background(), "GET", urlVersions, nil)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could I ask you to use the Updatecli custom httpclient from https://github.com/updatecli/updatecli/blob/main/pkg/core/httpclient/main.go

It will setup a few things like retry, user agent, etc.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @olblak, thank you for the feedback!

I have updated the implementation to import and use the custom Updatecli HTTP client (httpclient.NewRetryClient()) for querying the OpenTofu registry. The updated commit has been pushed to the branch.

@olblak olblak added bug Something isn't working resource-terraform labels Jul 17, 2026
@loispostula loispostula self-assigned this Jul 27, 2026

@loispostula loispostula left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Built and tested this locally against registry.opentofu.org/hashicorp/random 3.9.0 (15
published platforms). The approach works: before, the lock has 1 h1 and tofu init
adds the other 14; with this branch updatecli writes all 15 and tofu init leaves them
alone. Fixes #9213.

1. Doesn't compile. Provider.Hostname is svchost.Hostname, not string:

main.go:230:23: cannot use t.provider.Hostname (variable of string type
svchost.Hostname) as string value in argument to strings.HasPrefix

Needs a string(...) conversion. CI never ran here (fork PR), hence not caught.

2. Empty hashes return as success. If packages is empty, the function returns
(nil, nil), the caller only falls back on err != nil, and Apply writes
hashes = [], emptying the block. Needs a len(uniqueHashes) == 0 guard.

3. spec.Platforms is silently ignored. Ran with platforms: [darwin_arm64], got
all 15. Probably the right lock file, but the field is documented as controlling this
and ReportConfig still reports it. Needs a log line and a docs update.

Minor:

  • The localhost http downgrade (228-231) is unreachable in production, the only caller gates on the opentofu hostname. An unexported registryBaseURL field set in New() would let the test inject instead, and makes httpClient mockable.
  • Hostname is hardcoded, so self-hosted registries get nothing.
  • v.Platforms[0] is arbitrary, prefer an entry from spec.Platforms.
  • http.MethodGet, and slices.Sort/slices.Compact over sort.Strings plus the manual dedup.

Tests cover the happy path only, and call the unexported function directly, so the routing condition in getProviderHashes is never exercised. Worth adding the hostname gate, non-200, and empty packages.

@olblak

olblak commented Aug 11, 2026

Copy link
Copy Markdown
Member

@prajaktaukirde Without pressure, would you have some time to look at @loispostula comment?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working resource-terraform

Projects

None yet

Development

Successfully merging this pull request may close these issues.

terraform/lock: only requested-platform h1: hashes are recorded, so tofu init rewrites the lock file (OpenTofu registry exposes all platforms)

3 participants